package com.ybkj.daijia.server;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.util.CollectionUtils;

import com.ybkj.daijia.PushDataV4;
import com.ybkj.daijia.serverUtils.SettingUtils;
import com.ybkj.daijia.api.gexin.GeTuiEmployV4;
import com.ybkj.daijia.api.jpush.JiGuangEmployV4;
import com.ybkj.daijia.common.Result;
import com.ybkj.daijia.server.model.Company;
import com.ybkj.daijia.server.model.Driver;
import com.ybkj.daijia.server.model.DriverRefuseRecord;
import com.ybkj.daijia.server.model.SmsTemplet;
import com.ybkj.daijia.server.model.SmsTemplet.SmsType;
import com.ybkj.daijia.server.scheduler.ThreadControl;
import com.ybkj.daijia.server.service.CompanyService;
import com.ybkj.daijia.server.service.DriverRefuseRecordService;
import com.ybkj.daijia.server.service.DriverService;
import com.ybkj.daijia.server.service.SmsService;
import com.ybkj.daijia.server.service.ZhuancheService;
import com.ybkj.daijia.server.zhuan.Car;
import com.ybkj.daijia.server.zhuan.Order;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.util.CollectionUtils;

@Slf4j
public class ZhuanOrderTimerTask extends TimerTask {

    private ApplicationEventMulticaster applicationEventMulticaster;
    /**
     * 第一阶段自动派单距离
     */
    private Double autoPaidanKm1;
    /**
     * 第一阶段自动派单时间
     */
    private Integer autoPaidanTime1;
    /**
     * 第二阶段自动派单距离
     */
    private Double autoPaidanKm2;
    /**
     * 第二阶段自动派单时间
     */
    private Integer autoPaidanTime2;
    /**
     * 第三阶段自动派单距离
     */
    private Double autoPaidanKm3;

    /**
     * 第三阶段自动派单时间
     */
    private Integer autoPaidanTime3;

    private Long orderId;

    private Double longitude;

    private Double latitude;

    /**
     * 派单的阶段
     */
    private int stage;

    public ZhuanOrderTimerTask(
        Double autoPaidanKm1, Integer autoPaidanTime1,
        Double autoPaidanKm2, Integer autoPaidanTime2,
        Double autoPaidanKm3, Integer autoPaidanTime3,
        ApplicationEventMulticaster applicationEventMulticaster,
        Long orderId, Double latitude, Double longitude, int stage) {

        this.autoPaidanKm1 = autoPaidanKm1;
        this.autoPaidanTime1 = autoPaidanTime1;
        this.autoPaidanKm2 = autoPaidanKm2;
        this.autoPaidanTime2 = autoPaidanTime2;
        this.autoPaidanKm3 = autoPaidanKm3;
        this.autoPaidanTime3 = autoPaidanTime3;
        this.applicationEventMulticaster = applicationEventMulticaster;

        this.orderId = orderId;
        this.latitude = latitude;
        this.longitude = longitude;
        this.stage = stage;
    }


    @Override
    public void run() {
        if (isEmpty()) {
            cancelTask(this);
        } else {
            ZhuancheService orderService = Config.getWac().getBean(ZhuancheService.class);
            Order order = orderService.findOne(orderId);
            if (null == order || !order.getStatus().equals(Order.ORDER_STATUS_NEW)) {
                cancelTask(this);
            } else {
                DriverService driverService = Config.getWac().getBean(DriverService.class);
                DriverRefuseRecordService orderRefuseRecordService = Config.getWac()
                    .getBean(DriverRefuseRecordService.class);
                //判断是否为预约订单
                if (1 == order.getBookStatus()) {
                    dealOrder(orderService, order, driverService, orderRefuseRecordService);
                } else {
                    //v1.2版本是三阶段派单, 一旦第三阶段都还没有找到合适司机, 意味着订单搁浅
                    //第一阶段派单
                    // TODO 新需求, 第三阶段派单没找到司机需要需要定时取消订单,并且推送消息给乘客,告诉乘客暂时没有找到司机, 是否取消订单.
                    if (stage == 1) {
                        sendDriverOrderByStep(orderService, order, driverService,
                            orderRefuseRecordService, autoPaidanKm1);
                        //第二阶段派单
                    } else if (stage == 2) {
                        sendDriverOrderByStep(orderService, order, driverService,
                            orderRefuseRecordService, autoPaidanKm2);
                        //第三阶段派单
                    } else if (stage == 3) {
                        dealOrder(orderService, order, driverService,
                            orderRefuseRecordService);
                    }
                }
            }
        }
    }

    /**
     * 根据阶段自动派单
     *
     * @param orderService
     * @param order
     * @param driverService
     * @param orderRefuseRecordService
     * @param autoPaidan
     */
    private void sendDriverOrderByStep(ZhuancheService orderService, Order order,
        DriverService driverService, DriverRefuseRecordService orderRefuseRecordService,
        Double autoPaidan) {
        if (ThreadControl.autoPaidanZhuanche) {
            List<Driver> drivers = driverService
                .zhuanListDrivers(order.getStartLng(), order.getStartLat(),
                    autoPaidan, null, order.getCarTypeId());
            if (CollectionUtils.isEmpty(drivers)) {
                //取消自动派单,并且开始下一个阶段
                cancelAndNextTask(this, stage + 1);
            } else {
                //符合条件的司机
                ZhuancheService zhuancheService = Config.getWac().getBean(ZhuancheService.class);
                // 循环查询符合条件的司机, 主要是2次检查和拒单检查
                Driver thisDriver = loopSelectDriver(orderService, order, orderRefuseRecordService,
                    drivers, zhuancheService);
                if (null == thisDriver) {
                    //取消自动派单,并且开始下一个阶段
                    cancelAndNextTask(this, stage + 1);
                } else {
                    //更改司机状态, 更改订单状态
                    Result<Order> result = orderService.autoPaidan(thisDriver, order);
                    //派单成功
                    if (result.isSuccess()) {
                        //推送消息给司机并发送短信
                        autoPaidan(order, thisDriver);
                        cancelTask(this);
                    } else {
                        atOnceCancelAndPaidan(this, stage);
                    }
                }
            }
        } else {
            //取消自动派单,并且开始下一个阶段
            cancelAndNextTask(this, stage + 1);
        }
    }

    /**
     * 处理自动派单的基本流程
     * 处理订单 根据条件查询司机, 过滤司机,二次检查, 自动派单, 并取消任务
     * 注意 一旦没有排除就会搁浅
     * @param orderService
     * @param order
     * @param driverService
     * @param orderRefuseRecordService
     */
    private void dealOrder(ZhuancheService orderService, Order order,
        DriverService driverService, DriverRefuseRecordService orderRefuseRecordService) {
        if (ThreadControl.autoPaidanZhuanche) {
            //根据距离查询在线空闲司机, 在更具carTypeId过滤司机, 最后根据收藏和距离排序
            List<Driver> drivers = driverService.zhuanListDrivers(order.getStartLng(), order.getStartLat(),
                    autoPaidanKm3, null, order.getCarTypeId());
            //符合条件的司机
            //查询不能接预约订单的司机
            ZhuancheService zhuancheService = Config.getWac().getBean(ZhuancheService.class);
            // 循环查询符合条件的司机, 主要是2次检查和拒单检查
            Driver thisDriver = loopSelectDriver(orderService, order, orderRefuseRecordService, drivers, zhuancheService);
            //开始派单
            if (null != thisDriver) {
                //又是一次拒单检查
                Long refuseRecord = orderRefuseRecordService.countByOrderIdEmployIdAndOrderType(
                        orderId, thisDriver.getId(), DriverRefuseRecord.OrderType.zhuanche.toString());
                if (refuseRecord == 0) {
                    //修改司机的状态
                    Result<Order> result = orderService.autoPaidan(thisDriver, order);
                    //派单成功
                    if (result.isSuccess()) {
                        //推送消息给司机并发送短信
                        autoPaidan(order, thisDriver);
                        cancelTask(this);
                    }
                }
            }
        }
    }

    /***
     * 循环查询符合条件的司机, 主要是2次检查和拒单检查
     * @param orderService
     * @param order
     * @param orderRefuseRecordService
     * @param drivers
     * @param zhuancheService
     * @return
     */
    private Driver loopSelectDriver(ZhuancheService orderService, Order order,
        DriverRefuseRecordService orderRefuseRecordService, List<Driver> drivers, ZhuancheService zhuancheService) {
        for (Driver driver : drivers) {
            //二次状态检查
            if (!driver.getIsFreeze() && driver.getStatus()
                .equals(Driver.DRIVER_ONLINE) && driver.getCarId() != null) {
                //查询司机是否可以继续接单 这里返回都为true, v1.2版本没有预约
                if (zhuancheService.findDriverBusy(driver.getId(), order.getBookStatus(), orderId)) {
                    Car car = orderService.findCar(driver.getCarId());
                    // 再次健在carType和司机业务
                    // TODO 这儿carTypeId不对就没法进行, 那获取司机时多弄出来的carRealType就没用了,设计矛盾了
                    if (car != null && car.getCarTypeId().equals(order.getCarTypeId())) {
                        if (driver.getDriverJobType().equals(Driver.DriverJobType.all)
                            || driver.getDriverJobType().contains(Driver.DriverJobType.zhuanche.toString())) {
                            //过滤没有拒绝过该订单的司机
                            Long refuseRecord = orderRefuseRecordService.countByOrderIdEmployIdAndOrderType(
                                    orderId, driver.getId(), DriverRefuseRecord.OrderType.zhuanche.toString());
                            //没有拒单记录
                            if (refuseRecord == 0) {
                                return driver;
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * 先取消订单, 在更具阶段再次创建线程派单
     *
     * @param orderTimerTask
     * @param stage
     */
    private void atOnceCancelAndPaidan(ZhuanOrderTimerTask orderTimerTask, int stage) {
        try {
            orderTimerTask.cancel();
            ThreadControl.TaskMaps.remove("task_" + orderId);
        } catch (Exception e) {
            if (log.isErrorEnabled()) {
                log.error("取消派单线程失败,", e);
            }
        }
        Timer timer = new Timer();
        timer.schedule(new ZhuanOrderTimerTask(
            autoPaidanKm1, autoPaidanTime1,
            autoPaidanKm2, autoPaidanTime2,
            autoPaidanKm3, autoPaidanTime3,
            applicationEventMulticaster,
            orderId, latitude, longitude, stage), 0);
        ThreadControl.TaskMaps.put("task_" + orderId, timer);
    }

    private void cancelTask(ZhuanOrderTimerTask orderTimerTask) {
        try {
            orderTimerTask.cancel();
            ThreadControl.TaskMaps.remove("task_" + orderId);
        } catch (Exception e) {
            if (log.isErrorEnabled()) {
                log.error("取消自动派单线程异常", e);
            }
        }
    }

    /***
     * 取消自动派单,并且开始下一个阶段
     * @param orderTimerTask
     * @param stage
     */
    private void cancelAndNextTask(ZhuanOrderTimerTask orderTimerTask, int stage) {
        try {
            orderTimerTask.cancel();
            ThreadControl.TaskMaps.remove("task_" + orderId);
        } catch (Exception e) {
            log.error("取消自动派单线程异常", e);
        }
        Timer timer = new Timer();
        if (stage == 2) {
            timer.schedule(new ZhuanOrderTimerTask(
                autoPaidanKm1, autoPaidanTime1,
                autoPaidanKm2, autoPaidanTime2,
                autoPaidanKm3, autoPaidanTime3,
                applicationEventMulticaster,
                orderId, latitude, longitude, stage), autoPaidanTime2 * 1000);
            ThreadControl.TaskMaps.put("task_" + orderId, timer);
        } else if (stage == 3) {
            timer.schedule(new ZhuanOrderTimerTask(
                    autoPaidanKm1, autoPaidanTime1,
                    autoPaidanKm2, autoPaidanTime2,
                    autoPaidanKm3, autoPaidanTime3,
                    applicationEventMulticaster,
                    orderId, latitude, longitude, stage), autoPaidanTime3 * 1000,
                autoPaidanTime3 * 1000);
            ThreadControl.TaskMaps.put("task_" + orderId, timer);
        }
    }

    private boolean isEmpty() {
        if (autoPaidanKm1 == null || autoPaidanTime1 == null ||
            autoPaidanKm2 == null || autoPaidanTime2 == null ||
            autoPaidanKm3 == null || autoPaidanTime3 == null ||
            orderId == null || longitude == null || latitude == null) {
            return true;
        }
        return false;
    }

    /***
     * 推送消息给司机并发送短信
     * @param order
     * @param driver
     */
    private void autoPaidan(Order order, Driver driver) {
        SettingUtils settingUtils = Config.getWac().getBean(SettingUtils.class);
        try {
            // 用极光发送信息给司机
            pushMsToDriverPhoneByJPush(order, driver, settingUtils, ",赶快打开司机端接单吧");
        } catch (IOException e) {
            log.error("auto error : ", e);
        }
        CompanyService companyService = Config.getWac().getBean(CompanyService.class);
        Company driverCompany = companyService.findOne(driver.getCompanyId());
        Company finalCompany = driverCompany;
        Company main = companyService.getMain();
        if (!main.getId().equals(driverCompany.getId()) && settingUtils.get().isSmsMainCompany()) {
            finalCompany = main;
        }
        try {
            SmsService smsService = Config.getWac().getBean(SmsService.class);
            SmsTemplet templet = smsService
                .findByAlias(finalCompany.getId(), SmsType.paiZhuancheOrder);
            if (null != templet && StringUtils.isNotBlank(templet.getContent())) {
                DateFormat format = new SimpleDateFormat("HH:mm");
                String serverTime = format.format(order.getServerTime());
                smsService.sendSms(driver.getPhone(), "paiZhuancheOrder", "{\"订单号\":\"" + "***"
                        + order.getOrderNo().substring(8) + "\",\"客户姓名\":\"" + order.getPassengerName()
                        + "\",\"客户电话\":\"" + order.getPassengerPhone() + "\",\"预约时间\":\"" + serverTime
                        + "\",\"预约地点\":\"" + order.getStartAddress() + "\"}", finalCompany.getId(), 0,
                    finalCompany.getSignName());
            }
        } catch (Exception e) {
            log.error("专车自动派单短信  发送短信发生异常:", e);
        }
    }

    /***
     * 用极光发送信息给司机
     * V1.2还时个推为主, 但是后面会取消个推
     * @param order
     * @param driver
     * @param settingUtils
     * @param
     * @throws IOException
     */
    public static void pushMsToDriverPhoneByJPush(Order order, Driver driver,
        SettingUtils settingUtils,
        String s) throws IOException {
        PushDataV4 pushDataV4 = new PushDataV4();
        pushDataV4.setCode("0X03");
        pushDataV4.setData(order.getId());
        pushDataV4.setType("0X01");
        pushDataV4.setSound("beep_3");
        Map<String, String> extra = new HashMap<String, String>();
        extra.put("content", "您有新的工单啦,单号:" + order.getOrderNo() + s);
        pushDataV4.setExtra(extra);
        boolean getuiOnline = false;
        if (StringUtils.isNotBlank(driver.getUserID())) {
            getuiOnline = GeTuiEmployV4.getClientOnline(driver.getUserID(), settingUtils.get());
        }
        if (getuiOnline) {
            GeTuiEmployV4.push(driver, pushDataV4, settingUtils.get());
        } else {
            if (StringUtils.isNotBlank(driver.getRegistrationId())) {
                JiGuangEmployV4.push(driver, pushDataV4, settingUtils.get());
            }
        }
    }

}
